Skip to main content

Table Creation Code Examples

Basic Table Creation​

Simple 2x2 Table​

using DocumentFormat.OpenXml.Wordprocessing;

public static Table CreateSimpleTable()
{
var table = new Table();

// Table properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
)
);
table.AppendChild(tableProperties);

// Table grid (2 columns)
var tableGrid = new TableGrid(
new GridColumn { Width = "3000" },
new GridColumn { Width = "3000" }
);
table.AppendChild(tableGrid);

// Row 1
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));
row1.AppendChild(CreateCell("Header 1", 3000, bold: true));
row1.AppendChild(CreateCell("Header 2", 3000, bold: true));
table.AppendChild(row1);

// Row 2
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));
row2.AppendChild(CreateCell("Data 1", 3000));
row2.AppendChild(CreateCell("Data 2", 3000));
table.AppendChild(row2);

return table;
}

private static TableCell CreateCell(string text, int width, bool bold = false)
{
var cell = new TableCell();

// Cell properties
cell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa }
));

// Paragraph with text
var paragraph = new Paragraph();
var run = new Run();

if (bold)
{
run.AppendChild(new RunProperties(new Bold()));
}

run.AppendChild(new Text(text));
paragraph.AppendChild(run);
cell.AppendChild(paragraph);

return cell;
}

AppraiSys Pattern: Executive Summary Table​

From SubjectPropertyInformationSubstitutor.cs:

private Table CreateExecutiveSummaryTable(SubjectProperty property)
{
var table = new Table();

// Table properties
var tableProperties = new TableProperties(
// 90% width
new TableWidth { Width = "4500", Type = TableWidthUnitValues.Pct },

// Lightning borders
new TableBorders(
new TopBorder { Val = BorderValues.Lightning2 },
new LeftBorder { Val = BorderValues.Lightning2 },
new BottomBorder { Val = BorderValues.Lightning2 },
new RightBorder { Val = BorderValues.Lightning2 },
new InsideHorizontalBorder { Val = BorderValues.Lightning2 },
new InsideVerticalBorder { Val = BorderValues.None } // No vertical borders
),

// Row can't split across pages
new TableRowProperties(new CantSplit()),

// Fixed layout
new TableLayout { Type = TableLayoutValues.Fixed },

// Center table
new TableJustification { Val = TableRowAlignmentValues.Center }
);
table.AppendChild(tableProperties);

// Grid: 2 equal columns
var tableGrid = new TableGrid(
new GridColumn { Width = "3000" },
new GridColumn { Width = "3000" }
);
table.AppendChild(tableGrid);

// Add rows
AddTableRow(table, "Property Address:", property.Address);
AddTableRow(table, "Property Type:", property.PropertyType);
AddTableRow(table, "Year Built:", property.YearBuilt?.ToString());
AddTableRow(table, "Square Footage:", property.GrossLivingArea?.ToString("N0"));
AddTableRow(table, "Lot Size:", property.LotSize?.ToString("N0") + " sq ft");
AddTableRow(table, "Appraised Value:", "$" + property.AppraisedValue?.ToString("N0"));

return table;
}

private void AddTableRow(Table table, string label, string value)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));

// Label cell (bold)
var labelCell = CreateCell(label, 3000, bold: true, alignment: JustificationValues.Right);
row.AppendChild(labelCell);

// Value cell
var valueCell = CreateCell(value ?? "", 3000, alignment: JustificationValues.Left);
row.AppendChild(valueCell);

table.AppendChild(row);
}

Advanced Cell Creation​

Cell with Alignment and Formatting​

private static TableCell CreateCell(
string text,
int width,
bool bold = false,
JustificationValues alignment = JustificationValues.Left,
string backgroundColor = null,
VerticalTextAlignmentValues verticalAlign = VerticalTextAlignmentValues.Top)
{
var cell = new TableCell();

// Cell properties
var cellProperties = new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa },
new TableCellVerticalAlignment { Val = verticalAlign }
);

// Background color
if (backgroundColor != null)
{
cellProperties.AppendChild(new Shading
{
Fill = backgroundColor,
Val = ShadingPatternValues.Clear
});
}

cell.AppendChild(cellProperties);

// Paragraph
var paragraph = new Paragraph();

// Paragraph properties
var paragraphProperties = new ParagraphProperties(
new Justification { Val = alignment }
);
paragraph.AppendChild(paragraphProperties);

// Run
var run = new Run();

// Run properties
if (bold)
{
var runProperties = new RunProperties(new Bold());
run.AppendChild(runProperties);
}

run.AppendChild(new Text(text));
paragraph.AppendChild(run);
cell.AppendChild(paragraph);

return cell;
}

Cell Merging​

Horizontal Merge (Spanning Columns)​

public static Table CreateTableWithMergedCells()
{
var table = new Table();

// Properties and grid
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
table.AppendChild(tableProperties);

var tableGrid = new TableGrid(
new GridColumn { Width = "2000" },
new GridColumn { Width = "2000" },
new GridColumn { Width = "2000" }
);
table.AppendChild(tableGrid);

// Row 1: Merged header spanning all 3 columns
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));

var mergedCell = new TableCell();
mergedCell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "6000", Type = TableWidthUnitValues.Dxa },
new GridSpan { Val = 3 }, // Span 3 columns
new Shading { Fill = "CCCCCC" }
));
mergedCell.AppendChild(CreateParagraph("Merged Header", bold: true, centered: true));
row1.AppendChild(mergedCell);
table.AppendChild(row1);

// Row 2: Normal cells
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));
row2.AppendChild(CreateCell("Cell 1", 2000));
row2.AppendChild(CreateCell("Cell 2", 2000));
row2.AppendChild(CreateCell("Cell 3", 2000));
table.AppendChild(row2);

return table;
}

Vertical Merge (Spanning Rows)​

public static Table CreateTableWithVerticalMerge()
{
var table = new Table();

// Properties and grid
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
table.AppendChild(tableProperties);

var tableGrid = new TableGrid(
new GridColumn { Width = "2000" },
new GridColumn { Width = "4000" }
);
table.AppendChild(tableGrid);

// Row 1: Start vertical merge
var row1 = new TableRow();
row1.AppendChild(new TableRowProperties(new CantSplit()));

var cell1 = new TableCell();
cell1.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Restart } // Start merge
));
cell1.AppendChild(CreateParagraph("Merged Cell", bold: true));
row1.AppendChild(cell1);

row1.AppendChild(CreateCell("Row 1 Data", 4000));
table.AppendChild(row1);

// Row 2: Continue vertical merge
var row2 = new TableRow();
row2.AppendChild(new TableRowProperties(new CantSplit()));

var cell2 = new TableCell();
cell2.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Continue } // Continue merge
));
cell2.AppendChild(CreateParagraph("")); // Empty paragraph required
row2.AppendChild(cell2);

row2.AppendChild(CreateCell("Row 2 Data", 4000));
table.AppendChild(row2);

// Row 3: Continue vertical merge
var row3 = new TableRow();
row3.AppendChild(new TableRowProperties(new CantSplit()));

var cell3 = new TableCell();
cell3.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "2000", Type = TableWidthUnitValues.Dxa },
new VerticalMerge { Val = MergedCellValues.Continue }
));
cell3.AppendChild(CreateParagraph(""));
row3.AppendChild(cell3);

row3.AppendChild(CreateCell("Row 3 Data", 4000));
table.AppendChild(row3);

return table;
}

Property Images Table (AppraiSys)​

public static Table CreatePropertyImagesTable(List<ImageData> images, int columns = 3)
{
var table = new Table();

// Table properties
var tableProperties = new TableProperties(
new TableStyle { Val = "PropertyImagesTable" },
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableJustification { Val = TableRowAlignmentValues.Center },
new TableCellSpacing { Width = "100", Type = TableWidthUnitValues.Dxa },
new TableBorders(
new TopBorder { Val = BorderValues.None },
new BottomBorder { Val = BorderValues.None },
new LeftBorder { Val = BorderValues.None },
new RightBorder { Val = BorderValues.None },
new InsideHorizontalBorder { Val = BorderValues.None },
new InsideVerticalBorder { Val = BorderValues.None }
)
);
table.AppendChild(tableProperties);

// Grid
var columnWidth = 5000 / columns;
var tableGrid = new TableGrid();
for (int i = 0; i < columns; i++)
{
tableGrid.AppendChild(new GridColumn { Width = columnWidth.ToString() });
}
table.AppendChild(tableGrid);

// Add rows
int imageIndex = 0;
while (imageIndex < images.Count)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));

for (int col = 0; col < columns; col++)
{
if (imageIndex < images.Count)
{
var imageCell = CreateImageCell(images[imageIndex], columnWidth);
row.AppendChild(imageCell);
imageIndex++;
}
else
{
// Empty cell
row.AppendChild(CreateCell("", columnWidth));
}
}

table.AppendChild(row);
}

return table;
}

private static TableCell CreateImageCell(ImageData imageData, int width)
{
var cell = new TableCell();

cell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = width.ToString(), Type = TableWidthUnitValues.Dxa },
new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Top }
));

// Add image paragraph
var paragraph = new Paragraph();
paragraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));

// TODO: Add actual image drawing element here
// (See Image Handling section)

cell.AppendChild(paragraph);

// Caption paragraph
if (!string.IsNullOrEmpty(imageData.Caption))
{
var captionParagraph = new Paragraph();
captionParagraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));

var run = new Run();
run.AppendChild(new RunProperties(
new FontSize { Val = "18" }, // 9pt
new Italic()
));
run.AppendChild(new Text(imageData.Caption));

captionParagraph.AppendChild(run);
cell.AppendChild(captionParagraph);
}

return cell;
}

Table with Custom Borders​

public static Table CreateCustomBorderTable()
{
var table = new Table();

var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
// Thick top border
new TopBorder
{
Val = BorderValues.Single,
Size = 24, // 3pt
Color = "000000"
},
// Thin side borders
new LeftBorder
{
Val = BorderValues.Single,
Size = 4, // 0.5pt
Color = "CCCCCC"
},
new RightBorder
{
Val = BorderValues.Single,
Size = 4,
Color = "CCCCCC"
},
// Thick bottom border
new BottomBorder
{
Val = BorderValues.Single,
Size = 24,
Color = "000000"
},
// Dotted inside horizontal
new InsideHorizontalBorder
{
Val = BorderValues.Dotted,
Size = 4,
Color = "CCCCCC"
},
// No inside vertical
new InsideVerticalBorder { Val = BorderValues.None }
)
);
table.AppendChild(tableProperties);

// Add grid and rows...

return table;
}

Dynamic Table Generation​

Create Table from Data​

public static Table CreateTableFromData<T>(
List<T> data,
Dictionary<string, Func<T, string>> columns,
bool headerRow = true)
{
var table = new Table();

// Properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
)
);
table.AppendChild(tableProperties);

// Grid
int columnCount = columns.Count;
int columnWidth = 5000 / columnCount;

var tableGrid = new TableGrid();
for (int i = 0; i < columnCount; i++)
{
tableGrid.AppendChild(new GridColumn { Width = columnWidth.ToString() });
}
table.AppendChild(tableGrid);

// Header row
if (headerRow)
{
var headerRow = new TableRow();
headerRow.AppendChild(new TableRowProperties(new CantSplit()));

foreach (var column in columns.Keys)
{
var cell = CreateCell(
column,
columnWidth,
bold: true,
backgroundColor: "CCCCCC",
alignment: JustificationValues.Center
);
headerRow.AppendChild(cell);
}

table.AppendChild(headerRow);
}

// Data rows
foreach (var item in data)
{
var dataRow = new TableRow();
dataRow.AppendChild(new TableRowProperties(new CantSplit()));

foreach (var columnFunc in columns.Values)
{
var value = columnFunc(item);
var cell = CreateCell(value, columnWidth);
dataRow.AppendChild(cell);
}

table.AppendChild(dataRow);
}

return table;
}

// Usage:
var comparables = GetComparableProperties();
var table = CreateTableFromData(
comparables,
new Dictionary<string, Func<Comparable, string>>
{
{ "Address", c => c.Address },
{ "Price", c => "$" + c.Price.ToString("N0") },
{ "Sq Ft", c => c.SquareFeet.ToString("N0") },
{ "Beds", c => c.Bedrooms.ToString() },
{ "Baths", c => c.Bathrooms.ToString("F1") }
}
);

Nested Tables​

Table Inside Table Cell​

public static Table CreateNestedTable()
{
var outerTable = new Table();

// Outer table properties
var outerTableProps = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct }
);
outerTable.AppendChild(outerTableProps);

var outerGrid = new TableGrid(
new GridColumn { Width = "5000" }
);
outerTable.AppendChild(outerGrid);

// Outer row
var outerRow = new TableRow();
outerRow.AppendChild(new TableRowProperties(new CantSplit()));

var outerCell = new TableCell();
outerCell.AppendChild(new TableCellProperties(
new TableCellWidth { Width = "5000", Type = TableWidthUnitValues.Dxa }
));

// Header paragraph
var headerPara = new Paragraph();
var headerRun = new Run();
headerRun.AppendChild(new RunProperties(new Bold()));
headerRun.AppendChild(new Text("Container"));
headerPara.AppendChild(headerRun);
outerCell.AppendChild(headerPara);

// *** NESTED TABLE ***
var innerTable = new Table();
var innerTableProps = new TableProperties(
new TableWidth { Width = "4500", Type = TableWidthUnitValues.Dxa }
);
innerTable.AppendChild(innerTableProps);

var innerGrid = new TableGrid(
new GridColumn { Width = "2250" },
new GridColumn { Width = "2250" }
);
innerTable.AppendChild(innerGrid);

// Inner row
var innerRow = new TableRow();
innerRow.AppendChild(new TableRowProperties(new CantSplit()));
innerRow.AppendChild(CreateCell("Nested 1", 2250));
innerRow.AppendChild(CreateCell("Nested 2", 2250));
innerTable.AppendChild(innerRow);

// Add nested table to outer cell
outerCell.AppendChild(innerTable);

outerRow.AppendChild(outerCell);
outerTable.AppendChild(outerRow);

return outerTable;
}

Helper Methods​

Create Paragraph​

private static Paragraph CreateParagraph(
string text,
bool bold = false,
bool centered = false)
{
var paragraph = new Paragraph();

if (centered)
{
paragraph.AppendChild(new ParagraphProperties(
new Justification { Val = JustificationValues.Center }
));
}

var run = new Run();

if (bold)
{
run.AppendChild(new RunProperties(new Bold()));
}

run.AppendChild(new Text(text));
paragraph.AppendChild(run);

return paragraph;
}

Complete Example: Comparables Table​

public static Table CreateComparablesTable(
SubjectProperty subject,
List<Comparable> comparables)
{
var table = new Table();

// Properties
var tableProperties = new TableProperties(
new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
new TableBorders(
new TopBorder { Val = BorderValues.Single, Size = 4 },
new BottomBorder { Val = BorderValues.Single, Size = 4 },
new LeftBorder { Val = BorderValues.Single, Size = 4 },
new RightBorder { Val = BorderValues.Single, Size = 4 },
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4 },
new InsideVerticalBorder { Val = BorderValues.Single, Size = 4 }
),
new TableLayout { Type = TableLayoutValues.Fixed }
);
table.AppendChild(tableProperties);

// Grid: Subject + 3 comparables
var tableGrid = new TableGrid(
new GridColumn { Width = "2000" }, // Field name
new GridColumn { Width = "1500" }, // Subject
new GridColumn { Width = "1000" }, // Comp 1
new GridColumn { Width = "1000" }, // Comp 2
new GridColumn { Width = "1000" } // Comp 3
);
table.AppendChild(tableGrid);

// Header row
AddHeaderRow(table, comparables.Count);

// Data rows
AddFieldRow(table, "Address",
subject.Address,
comparables.Select(c => c.Address).ToArray());

AddFieldRow(table, "Sale Price",
"$" + subject.AppraisedValue?.ToString("N0"),
comparables.Select(c => "$" + c.SalePrice.ToString("N0")).ToArray());

AddFieldRow(table, "Square Feet",
subject.GrossLivingArea?.ToString("N0"),
comparables.Select(c => c.SquareFeet.ToString("N0")).ToArray());

AddFieldRow(table, "Bedrooms",
subject.Bedrooms?.ToString(),
comparables.Select(c => c.Bedrooms.ToString()).ToArray());

AddFieldRow(table, "Bathrooms",
subject.Bathrooms?.ToString("F1"),
comparables.Select(c => c.Bathrooms.ToString("F1")).ToArray());

return table;
}

private static void AddHeaderRow(Table table, int comparableCount)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));

row.AppendChild(CreateCell("Item", 2000, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));
row.AppendChild(CreateCell("Subject", 1500, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));

for (int i = 0; i < comparableCount; i++)
{
row.AppendChild(CreateCell($"Comp {i + 1}", 1000, bold: true,
backgroundColor: "CCCCCC", alignment: JustificationValues.Center));
}

table.AppendChild(row);
}

private static void AddFieldRow(Table table, string fieldName,
string subjectValue, params string[] comparableValues)
{
var row = new TableRow();
row.AppendChild(new TableRowProperties(new CantSplit()));

row.AppendChild(CreateCell(fieldName, 2000, bold: true,
alignment: JustificationValues.Right));
row.AppendChild(CreateCell(subjectValue ?? "", 1500,
alignment: JustificationValues.Center));

foreach (var value in comparableValues)
{
row.AppendChild(CreateCell(value ?? "", 1000,
alignment: JustificationValues.Center));
}

table.AppendChild(row);
}

Next Steps​

➡️ Next: Image Handling

Related:


💡 Remember: Every table cell must contain at least one paragraph. Always use CantSplit() for professional-looking tables!